using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.SharePoint.Administration;
using System.Data.SqlClient;
using System.Web.Security;
using System.Web.Configuration;
using System.Configuration;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using Microsoft.SharePoint;

namespace SPAuthTool2007 {
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window {
        public Window1() {
            InitializeComponent();
        }

        private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (e.AddedItems != null && e.AddedItems.Count > 0) {
                TabItem tabItem = e.AddedItems[0] as TabItem;
                int tabIndex = tabControl1.Items.IndexOf(tabItem);

                if (tabItem != null) {
                    if (tabIndex == 0) {
                        previousButton.IsEnabled = false;
                        nextButton.IsEnabled = true;
                        finishButton.IsEnabled = false;
                    } else if (tabIndex == tabControl1.Items.Count - 1) {
                        previousButton.IsEnabled = true;
                        nextButton.IsEnabled = false;
                        finishButton.IsEnabled = true;
                    } else {
                        previousButton.IsEnabled = true;
                        nextButton.IsEnabled = true;
                        finishButton.IsEnabled = false;
                    }
                }
            }
        }

        private void previousButton_Click(object sender, RoutedEventArgs e) {
            tabControl1.SelectedIndex--;
        }

        private void nextButton_Click(object sender, RoutedEventArgs e) {
            tabControl1.SelectedIndex++;
        }

        private void finishButton_Click(object sender, RoutedEventArgs e) {
            // Do stuff.
            if (!AddFBAUserToSQL()) {
                return;
            }
            EditDefaultZoneWebConfig();
            EditFBAZoneWebConfig();
            EditCentralAdminWebConfig();
            UpdateAuthenticationProvider();
            AddFBAUserToSharePoint();

            MessageBox.Show("Done!");
        }

        private void UpdateAuthenticationProvider() {
            SPWebApplication webApplication = webApplicationComboBox.SelectedItem as SPWebApplication;

            if (webApplication != null) {
                SPIisSettings settings = webApplication.IisSettings[(SPUrlZone) zoneComboBox.SelectedItem];
                if (anonymousCheckBox.IsChecked.HasValue) {
                    settings.AllowAnonymous = anonymousCheckBox.IsChecked.Value;
                }
                settings.AuthenticationMode = AuthenticationMode.Forms;
                settings.EnableClientIntegration = false;
                settings.MembershipProvider = membershipProviderNameTextBox.Text;
                settings.RoleManager = roleProviderNameTextBox.Text;
                webApplication.Update();
            }
        }

        private void AddFBAUserToSharePoint() {
            SPWebApplication webApplication = webApplicationComboBox.SelectedItem as SPWebApplication;

            if (webApplication != null) {
                using (SPSite siteCollection = webApplication.Sites[0]) {
                    siteCollection.RootWeb.SiteAdministrators.Add(membershipProviderNameTextBox.Text + ":" + userNameTextBox.Text, null, userNameTextBox.Text, null);
                }
            }
        }

        private void EditFBAZoneWebConfig() {
            Configuration configuration = GetWebConfiguration(webApplicationComboBox.SelectedItem as SPWebApplication, (SPUrlZone) zoneComboBox.SelectedItem);

            UpdateConnectionStrings(configuration);
            UpdateRoleProvider(configuration, roleProviderNameTextBox.Text);
            UpdateMembershipProvider(configuration);

            configuration.Save();
        }

        private void EditDefaultZoneWebConfig() {
            Configuration configuration = GetWebConfiguration(webApplicationComboBox.SelectedItem as SPWebApplication, SPUrlZone.Default);

            UpdateConnectionStrings(configuration);
            UpdateRoleProvider(configuration, roleProviderNameTextBox.Text);
            UpdateMembershipProvider(configuration);

            configuration.Save();
        }

        private void EditCentralAdminWebConfig() {
            Configuration configuration = GetWebConfiguration(SPAdministrationWebApplication.GetInstanceLocalToFarm(SPFarm.Local), SPUrlZone.Default);

            UpdateConnectionStrings(configuration);
            UpdateRoleProvider(configuration, "AspNetWindowsTokenRoleProvider");

            configuration.Save();
        }

        private void UpdateMembershipProvider(Configuration configuration) {
            SystemWebSectionGroup systemWeb = configuration.SectionGroups["system.web"] as SystemWebSectionGroup;

            if (systemWeb != null) {
                MembershipSection membership = systemWeb.Sections["membership"] as MembershipSection;

                if (membership != null) {
                    membership.DefaultProvider = membershipProviderNameTextBox.Text;

                    membership.Providers.Remove(membershipProviderNameTextBox.Text);

                    Type membershipProviderType = typeof(SqlMembershipProvider);

                    ProviderSettings membershipSetings = new ProviderSettings(membershipProviderNameTextBox.Text, membershipProviderType.AssemblyQualifiedName);

                    membershipSetings.Parameters.Add("applicationName", applicationNameTextBox.Text);
                    membershipSetings.Parameters.Add("enablePasswordReset", enablePasswordResetCheckBox.IsChecked.ToString());
                    membershipSetings.Parameters.Add("enablePasswordRetrieval", enablePasswordRetrievalCheckBox.IsChecked.ToString());
                    membershipSetings.Parameters.Add("maxInvalidPasswordAttempts", maxPasswordAttemptsTextBox.Text);
                    membershipSetings.Parameters.Add("minRequiredPasswordLength", minPasswordLengthTextBox.Text);
                    membershipSetings.Parameters.Add("minRequiredNonalphanumericCharacters", minAlphaNumCharsTextBox.Text);
                    membershipSetings.Parameters.Add("passwordAttemptWindow", passwordAttemptWindowTextBox.Text);
                    membershipSetings.Parameters.Add("passwordStrengthRegularExpression", passwordStrengthRegExTextBox.Text);
                    membershipSetings.Parameters.Add("requiresQuestionAndAnswer", requireQuestionAndAnswerCheckBox.IsChecked.ToString());
                    membershipSetings.Parameters.Add("requiresUniqueEmail", requireUniqueEmailCheckBox.IsChecked.ToString());
                    membershipSetings.Parameters.Add("connectionStringName", connectionNameTextBox.Text);

                    membership.Providers.Add(membershipSetings);
                }
            }
        }

        private void UpdateRoleProvider(Configuration configuration, string defaultProvider) {
            SystemWebSectionGroup systemWeb = configuration.SectionGroups["system.web"] as SystemWebSectionGroup;

            if (systemWeb != null) {
                RoleManagerSection roleManager = systemWeb.Sections["roleManager"] as RoleManagerSection;

                if (roleManager != null) {
                    roleManager.Enabled = true;
                    roleManager.DefaultProvider = defaultProvider;

                    foreach (ProviderSettings provider in roleManager.Providers) {
                        if (provider.Name == roleProviderNameTextBox.Text) {
                            roleManager.Providers.Remove(roleProviderNameTextBox.Text);
                        }
                    }

                    Type roleProviderType = typeof(SqlRoleProvider);

                    ProviderSettings roleProviderSettings = new ProviderSettings(roleProviderNameTextBox.Text, roleProviderType.AssemblyQualifiedName);

                    roleProviderSettings.Parameters.Add("applicationName", applicationNameTextBox.Text);
                    roleProviderSettings.Parameters.Add("connectionStringName", connectionNameTextBox.Text);

                    roleManager.Providers.Add(roleProviderSettings);
                }
            }
        }

        private void UpdateConnectionStrings(Configuration configuration) {
            configuration.ConnectionStrings.ConnectionStrings.Remove(connectionNameTextBox.Text);
            configuration.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(connectionNameTextBox.Text, GetConnectionString(), "System.Data.SqlClient"));
        }

        private Configuration GetWebConfiguration(SPWebApplication webApplication, SPUrlZone zone) {
            string path = GetWebSitePath(webApplication, zone);
            path += "\\web.config";
            BackupFile(path);

            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = path;

            return ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
        }

        private void BackupFile(string path) {
            string newPath = System.IO.Path.GetDirectoryName(path) + "\\";
            newPath += System.IO.Path.GetFileNameWithoutExtension(path) + " - Backup " + DateTime.Now.ToString("yyyyMMdd HHmm");
            newPath += System.IO.Path.GetExtension(path);

            File.Copy(path, newPath);
        }

        private string GetWebSitePath(SPWebApplication webApplication, SPUrlZone zone) {
            string path = webApplication.GetIisSettingsWithFallback(zone).Path.FullName;

            return path;
        }

        private bool AddFBAUserToSQL() {
            SqlMembershipProvider provider = GetTestMembershipProvider();

            bool retval = provider.DeleteUser(userNameTextBox.Text, true);

            MembershipCreateStatus status;
            provider.CreateUser(userNameTextBox.Text, passwordBox1.Password, emailTextBox.Text, Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), true, Guid.NewGuid(), out status);

            if (status != MembershipCreateStatus.Success) {
                MessageBox.Show("Error creating FBA user:" + status);
                return false;
            }

            return true;
        }

        private SqlMembershipProvider GetTestMembershipProvider() {
            EnsureConnectionString();
            EnsureMembershipSection();

            SqlMembershipProvider provider = new SqlMembershipProvider();

            provider.ApplicationName = applicationNameTextBox.Text;

            NameValueCollection values = new NameValueCollection();
            values.Add("name", membershipProviderNameTextBox.Text);
            values.Add("applicationName", applicationNameTextBox.Text);
            values.Add("connectionStringName", connectionNameTextBox.Text);

            provider.Initialize(membershipProviderNameTextBox.Text, values);

            return provider;
        }

        private void EnsureMembershipSection() {
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            UpdateMembershipProvider(configuration);
            configuration.Save();
            ConfigurationManager.RefreshSection("system.web");
        }

        private void EnsureConnectionString() {
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            configuration.ConnectionStrings.ConnectionStrings.Clear();
            configuration.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(connectionNameTextBox.Text, GetConnectionString(), "System.Data.SqlClient"));
            configuration.Save();
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) {
            PopulateWebApplications();
        }

        private void PopulateWebApplications() {
            webApplicationComboBox.Items.Clear();

            SPFarm farm = SPFarm.Local;

            SPWebService service = farm.Services.GetValue<SPWebService>();

            foreach (SPWebApplication webApplication in service.WebApplications) {
                webApplicationComboBox.Items.Add(webApplication);
            }
        }

        private void refreshWebApplicationsButton_Click(object sender, RoutedEventArgs e) {
            PopulateWebApplications();
        }

        private void webApplicationComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (e.AddedItems != null && e.AddedItems.Count > 0) {
                SPWebApplication webApplication = e.AddedItems[0] as SPWebApplication;

                if (webApplication != null) {
                    zoneComboBox.Items.Clear();

                    foreach (SPUrlZone zone in Enum.GetValues(typeof(SPUrlZone))) {
                        if (zone != SPUrlZone.Default) {
                            SPAlternateUrl url = webApplication.AlternateUrls.GetResponseUrl(zone, false);

                            if (url != null) {
                                zoneComboBox.Items.Add(zone);
                            }
                        }
                    }
                }
            }
        }

        private void testButton_Click(object sender, RoutedEventArgs e) {
            TestConnectionString();
        }

        private bool TestConnectionString() {
            try {
                using (SqlConnection connection = new SqlConnection(GetConnectionString())) {
                    connection.Open();
                    connection.Close();
                }

                MessageBox.Show("The connection was successful.");

                return true;
            } catch (Exception ex) {
                MessageBox.Show("The connection was not successful.  Exception: " + ex.ToString());
            }

            return false;
        }

        private string GetConnectionString() {
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
            builder.DataSource = serverNameTextBox.Text;
            builder.InitialCatalog = databaseNameTextBox.Text;
            builder.IntegratedSecurity = true;
            return builder.ConnectionString;
        }

        private void createButton_Click(object sender, RoutedEventArgs e) {
            MessageBox.Show("Not implemented yet...");
        }

        private void extendButton_Click(object sender, RoutedEventArgs e) {
            MessageBox.Show("Not implemented yet...");
        }

    }
}
